/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "ui节点面板.h"

#include <节点/socket_utils.h>
#include <几何图形/图形相交.h>
#include "节点操作.h"
#include "basic_vec.h"

//视口和面板实现文件相互依赖
#include "./ui节点视口.h"



static S_UI创建环境* debug_g_ctx;

using namespace std;
//static fp_节点创建视口回调 g_节点创建视口回调 = 0;




vec2 C_ui节点插座::m_起点 = { 0,0 };
vec2 C_ui节点插座::m_终点 = { 0,0 };

bool C_节点面板::m_移动面板 = false;

std::map<std::string, f_节点面板构建_回调函数指针> C_节点面板::g节点面板构建函数;
std::map<std::string, f_节点面板重置_回调函数指针> C_节点面板::g节点面板重置函数;




static S_插座拖放数据 g插座拖放数据;



static S_NodeLink*	gLink = 0;
//static float32		g_节点面板宽度 = 92.0f;
static vec2			g插座大小 = { 12, 12 };
static vec2			g纵向插座大小 = { 12, 18 };
static vec2			g左边插座大小 = { 4,8 };
static vec2			g插座坐标 = {};
static vec2			g鼠标起始坐标 = {};
static float32		g插座宽度 = 10;
static float32		g内部按钮大小 = 10;


static bool			g正在链接 = false;
static bool			g线预链接 = false;
static S_RGBA8UI	g全屏链接线颜色 = S_UI主题::uic_节点面板 + S_RGBA8UI{ 10, 10, 40, 0 };

float32 C_节点面板::m_链接点直径 = 16;


C_节点操作_移动节点* C_节点操作_移动节点::g当前移动操作 = nullptr;
static C_节点操作_删除节点* g当前删除面板操作 = nullptr;





struct S_节点视口链接节点树数据 {
	C_节点基类* m_Node;
};
static S_节点视口链接节点树数据 g节点视口链接节点树数据;


static void on_节点全屏链接线绘制(C_Widget* self, S_2D画布* 画布) {
	S_框架::m_全屏链接线背景绘制->m_属性 = f_vg_gen属性(画布);
	S_凸边图元 图元 = {};
	图元.属性 = f_vg_get属性指针(画布, S_框架::m_全屏链接线背景绘制->m_属性);
	S_框架::m_全屏链接线背景绘制->f_Draw(画布, 图元, E_笔刷类型::e_单色描边);

	S_框架::m_全屏链接线绘制->f_Draw(画布, S_框架::m_全屏链接线背景绘制->m_属性, E_笔刷类型::e_单色填充);
	//节点面板->m_连接线绘制.f_Draw点(画布, 节点面板->m_背景绘制.m_属性, 2.0, E_笔刷类型::e_单色描边);
	//节点面板->m_图标绘制.f_Draw纹理(画布, 节点面板->m_背景绘制.m_属性, S_主题颜色::uic_节点图标集);
	//节点面板->m_文本绘制.f_Draw文本(画布, self->m_UIctx->m_文字字号, 节点面板->m_背景绘制.m_属性);
}

static void on_节点全屏链接线变换修改(C_Widget* self) {
	S_框架::m_全屏链接线绘制->f_alloc(2, S_主题颜色::uic_节点剪刀线);
	//S_框架::m_全屏链接线绘制->f_set顶点(g鼠标起始坐标, g全屏链接线颜色);
	S_框架::m_全屏链接线绘制->f_set顶点(0, C_Widget::g_鼠标.gPos);
	S_框架::m_全屏链接线绘制->f_End();
	std::cout << "on_节点全屏链接线变换修改" << std::endl;
}

static bool on_节点全屏链接线鼠标移动(C_Widget* self, const ivec4& value) {
	//m_全屏链接线绘制.f_set顶点(0, C_Widget::g_鼠标.gPos);

	return false;
}

static E_事件是否传递 on_节点子集按钮准备拖动(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	f_widget_顶层窗口_push(S_框架::g_ui顶层画布, 0);

	C_节点面板* 节点 = dynamic_cast<C_节点面板*>(self->m_父部件);
	auto* 节点视口 = dynamic_cast<C_节点视口*>(节点->m_父部件);

	std::cout << "子集按钮准备拖动" << std::endl;
	g鼠标起始坐标 = C_Widget::g_鼠标.gPos;
	g插座拖放数据.发起的节点树 = 节点视口;
	g插座拖放数据.发起的节点 = 节点;

	data.m_Type = E_自定义拖放数据类型::e_拖放_节点子集按钮;
	data.m_Next = &g插座拖放数据;

	return E_事件是否传递::e_事件传递_终止;
}

static E_事件是否传递 on_节点子集按钮拖动(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	S_框架::m_全屏链接线绘制->f_set顶点(1, C_Widget::g_鼠标.gPos);
	return E_事件是否传递::e_事件传递_继续;
}

static bool f_节点子集按钮结束拖动(C_Widget* self, C_Widget* 拾取的部件, S_拖放数据& data) {
	f_widget_顶层窗口_pop(0);
	std::cout << "f_节点子集按钮结束拖动" <<  std::endl;
	C_节点面板* plane = static_cast<C_节点面板*>(self->m_父部件);
	switch (plane->m_NodeData->m_Type) {
	case E_节点类型::e_节点Type_材质: {
		//g节点视口链接节点树数据.m_Node = plane->m_NodeData;
		//data.m_Type = E_物体数据类型::e_节点视口链接节点树;
		//data.m_Next = &g节点视口链接节点树数据;
		break;
	}
	}

	//g插座拖放数据 = {};
	return true;
}





static vec2 f_计算连接点坐标(C_节点面板* 节点, C_ui节点插座* 插座) {
	vec2 坐标 = 节点->f_getOriginalPos() + 插座->f_getOriginalPos() + 插座->f_getOriginalSize() * 0.5f;
	return 坐标;
}

static void f_计算两连接点坐标(C_节点面板* 开始拖动拾取的节点,
	C_节点面板* 连接到的节点,
	C_ui节点插座* 开始拖动拾取的插座,
	C_ui节点插座* 结束拖动拾取的插座,
	vec2* 坐标) {

	坐标[0] = 开始拖动拾取的节点->f_getOriginalPos() + 开始拖动拾取的插座->f_getOriginalPos() + 开始拖动拾取的插座->f_getOriginalSize() / 2;
	坐标[1] = 连接到的节点->f_getOriginalPos() + 结束拖动拾取的插座->f_getOriginalPos() + 结束拖动拾取的插座->f_getOriginalSize() / 2;

}



void f_NodePlane_链接节点(C_节点面板* out节点, uint16 outSocketInID, C_节点面板* in节点, uint16 inSocketInID) {
	auto* out插座部件 = out节点->f_getOutSocket(outSocketInID);
	auto* in插座部件 = in节点->f_getInSocket(inSocketInID);

	gLink = f_genNodeLink();
	S_NodeLink* 替换的链接 = gLink->f_Link(in插座部件->m_SocketData, out插座部件->m_SocketData);

	//连接到的节点->f_动态添加删除插座(Si);
	//连接到的节点->f_插座变换更新();
	//连接到的节点->m_绘制属性更新 = true;
	//开始拖动拾取的节点->m_绘制属性更新 = true;

	//std::vector<S_NodeLink*> 替换的链接links;
	std::vector<S_链接线记录> 替换的链接links;
	if (替换的链接) {
		//操作记录
		if (替换的链接 != (S_NodeLink*)0xffffffffffffffff) {
			uvec2 r_id = 替换的链接->f_get链接线插座id();
			替换的链接links.push_back({ 替换的链接->m_插座in->f_getNode(), 替换的链接->m_插座out->f_getNode(), 替换的链接, r_id });
			//替换的链接links.push_back(替换的链接);
			替换的链接->m_插座out->m_UI部件->m_父部件->m_绘制属性更新 = true;
		}

		C_节点操作_切断链接* 断开 = new C_节点操作_切断链接(替换的链接links, gLink);
		gLink = nullptr;
	}
	else {
		f_NodeLine_回收(gLink);
	}
}

void f_NodePlane_切换插座类型(C_节点面板* 节点面板, E_插座方向 方向, uint16 loc, E_值类型 类型) {
	f_su_切换后端插座类型(节点面板->m_NodeData, 方向, loc, 类型);

}

vec2 f_NodePlane_get中心坐标(C_节点面板* 节点面板) {
	vec2 坐标 = 节点面板->m_内部面板->f_getOriginalPos() + 节点面板->m_内部面板->f_getOriginalSize() * 0.5;
	坐标 += 节点面板->m_NodeData->m_坐标;
	return 坐标;
}

vec2 f_NodePlane_get中心偏移(C_节点面板* 节点面板) {
	vec2 坐标 = 节点面板->m_内部面板->f_getOriginalPos() + 节点面板->m_内部面板->f_getOriginalSize() * 0.5;
	return 坐标;
}





static E_事件是否传递 f_插座准备拖动(C_Widget* 部件, const S_鼠标& 鼠标, S_拖放数据& data) {
	C_ui节点插座* 插座 = dynamic_cast<C_ui节点插座*>(部件);
	const C_节点面板* Node = 插座->m_NodePlane;
	g插座拖放数据.头 = 插座;
	g插座拖放数据.发起的节点树 = (C_节点视口*)Node->m_父部件;

	data.m_Type = E_自定义拖放数据类型::e_拖放_插座;
	data.m_Next = &g插座拖放数据;
	//cout << "f_插座准备拖动 Node == " << Node << endl;

	g插座坐标 = 插座->f_getOriginalPos() + Node->f_getOriginalPos();
	switch (Node->m_NodeData->f_get所在节点树()->m_布局方向) {
	case E_方向::e_横向: {
		g插座坐标 += 插座->f_getOriginalSize() * 0.5f;
		break;
	}
	case E_方向::e_纵向: {
		g插座坐标.x += 插座->f_getOriginalSize().x * 0.5f;

		if (插座->m_SocketData->f_isOut()) {
			g插座坐标.y += g插座大小.y;
		}
		else {
			g插座坐标.y += 插座->f_getOriginalSize().y - g插座大小.y;
		}
		break;
	}
	}

	C_节点视口* view = dynamic_cast<C_节点视口*>(插座->m_父部件->m_父部件);
	if (view) {
		g正在链接 = true;
	}
	//cout << "socket A == " << 插座 << endl;
	return E_事件是否传递::e_事件传递_继续;
}

static E_事件是否传递 on_插座拖动(C_Widget* 部件, const S_鼠标& 鼠标, S_拖放数据& data) {
	if (g线预链接) return E_事件是否传递::e_事件传递_继续;

	const C_ui节点插座* 插座 = dynamic_cast<C_ui节点插座*>(部件);
	const C_节点面板* Node = 插座->m_NodePlane;
	C_节点视口* view = dynamic_cast<C_节点视口*>(Node->m_父部件);

	vec2 局部位置 = (f_widget_get鼠标局部位置(鼠标.gPos, view) - view->m_扩展视口属性->m_中心) / Node->m_Scale.x;
	if (view) {
		switch (插座->m_SocketData->f_get方向()) {
		case E_插座方向::e_插座Type_输入: {
			view->f_连接线线尾拖动(局部位置, g插座坐标, S_主题颜色::uic_节点链接线);
			break;
		}
		case E_插座方向::e_插座Type_输出: {
			view->f_连接线线尾拖动(g插座坐标, 局部位置, S_主题颜色::uic_节点链接线);
			break;
		}
		}
	}

	return E_事件是否传递::e_事件传递_继续;
}

bool on_鼠标进入连接点(C_Widget* self, const S_鼠标& 鼠标) {
	C_节点视口* view = dynamic_cast<C_节点视口*>(self->m_父部件->m_父部件);
	C_ui节点插座* 插座 = dynamic_cast<C_ui节点插座*>(self);
	C_节点面板* Node = dynamic_cast<C_节点面板*>(插座->m_父部件);

	插座->m_颜色A = 插座->m_颜色B + S_RGBA8UI{150,150,10,0};
	Node->m_绘制属性更新 = true;
	//std::cout << "插座I:" << 插座->m_SocketData->m_Type << std::endl;
	if (view && g正在链接) {
		g线预链接 = true;
		vec2 局部位置 = f_widget_get鼠标局部位置(鼠标.gPos, view);
		

		局部位置 = 插座->f_getOriginalPos() + Node->f_getOriginalPos();
		switch (Node->m_NodeData->f_get所在节点树()->m_布局方向) {
		case E_方向::e_横向: {
			局部位置 += 插座->f_getOriginalSize() * 0.5f;
			break;
		}
		case E_方向::e_纵向: {
			局部位置.x += 插座->f_getOriginalSize().x * 0.5f;

			if (插座->m_SocketData->f_isOut()) {
				局部位置.y += g插座大小.y;
			}
			else {
				局部位置.y += 插座->f_getOriginalSize().y - g插座大小.y;
			}
			break;
		}
		}
		//vec2 插座坐标 = f_计算连接点坐标(dynamic_cast<C_节点面板*>(self->m_父部件), 插座);
		view->f_连接线线尾拖动(g插座坐标, 局部位置, {50,255,50,255});
	}
	return true;
}

bool on_鼠标离开连接点(C_Widget* self, const S_鼠标& 鼠标) {
	C_节点视口* view = dynamic_cast<C_节点视口*>(self->m_父部件->m_父部件);
	C_ui节点插座* 插座 = dynamic_cast<C_ui节点插座*>(self);
	if (view) {
		//view->f_线末端靠近点撤销();
	}
	插座->m_颜色A = 插座->m_颜色B;
	self->m_父部件->m_绘制属性更新 = true;
	g线预链接 = false;
	return true;
}


static bool f_插座结束拖动(struct C_Widget* 部件, C_Widget* 拾取的部件, S_拖放数据& data) {
	C_ui节点插座* 开始的的插座部件 = dynamic_cast<C_ui节点插座*>(部件);
	C_ui节点插座* 结束拖动拾取的插座 = dynamic_cast<C_ui节点插座*>(拾取的部件);
	
	g正在链接 = false;
	g线预链接 = false;

	C_节点视口* view = dynamic_cast<C_节点视口*>(开始的的插座部件->m_父部件->m_父部件);
	view->f_连接线线尾拖动结束();

	if (结束拖动拾取的插座 == 0 || data.m_Type != E_自定义拖放数据类型::e_拖放_插座) {
		//view->f_取消Link();
		return true;
	}

	S_插座拖放数据* t = (S_插座拖放数据*)data.m_Next;
	
	C_节点面板* 开始拖动拾取的节点 = t->头->m_NodePlane;
	C_节点面板* 连接到的节点 = 结束拖动拾取的插座->m_NodePlane;
	

	C_插座基类* So;
	C_插座基类* Si;
	
	vec2 计算后的插座坐标[2];
	//vec2 ev;

	C_ui节点插座* out插座部件 = 0;
	C_ui节点插座* in插座部件 = 0;
	if (结束拖动拾取的插座->m_SocketData->f_isOut()) {
		So = 结束拖动拾取的插座->m_SocketData;
		Si = t->头->m_SocketData;
		out插座部件 = 结束拖动拾取的插座;
		in插座部件 = t->头;
	}
	else {
		So = t->头->m_SocketData;
		Si = 结束拖动拾取的插座->m_SocketData;

		out插座部件 = t->头;
		in插座部件 = 结束拖动拾取的插座;
	}

	
	

	if (So && Si) {
		gLink = f_genNodeLink();
		S_NodeLink* 替换的链接 = gLink->f_Link(in插座部件->m_SocketData, out插座部件->m_SocketData);
		

		连接到的节点->f_动态添加插座(Si);
		连接到的节点->f_插座横向变换更新();
		连接到的节点->m_绘制属性更新 = true;
		开始拖动拾取的节点->m_绘制属性更新 = true;


		//std::vector<S_NodeLink*> 替换的链接links;
		std::vector<S_链接线记录> 替换的链接links;
		if (替换的链接) {
			//操作记录
			if (替换的链接 != (S_NodeLink*)0xffffffffffffffff) {
				uvec2 r_id = 替换的链接->f_get链接线插座id();
				替换的链接links.push_back({ 替换的链接->m_插座in->f_getNode(), 替换的链接->m_插座out->f_getNode(), 替换的链接, r_id });
				替换的链接->m_插座out->m_UI部件->m_父部件->m_绘制属性更新 = true;
			}


			C_节点操作_切断链接* 断开 = new C_节点操作_切断链接(替换的链接links, gLink);
			gLink = 0;
		}
		else {
			f_NodeLine_回收(gLink);
		}

		开始拖动拾取的节点->m_属性面板参数构建(view->m_属性栏, (S_结构对象指针)开始拖动拾取的节点);
		连接到的节点->m_属性面板参数构建(view->m_属性栏, (S_结构对象指针)连接到的节点);
		for (auto& node : view->m_焦点节点面板) {
			node->m_属性面板参数构建(view->m_属性栏, (S_结构对象指针)node);
		}
	}
	return true;
}





static void on_插座UI更新 (C_插座基类* socket) {
	C_ui节点插座* 插座 = dynamic_cast<C_ui节点插座*>(socket->m_UI部件);
	assert(插座 != nullptr);

	插座->m_SocketData = socket;
}

C_ui节点插座::C_ui节点插座(C_节点面板* node, C_插座基类* socket) : m_NodePlane(node), m_SocketData(socket) {
	socket->m_UI部件 = this;
	socket->on_UI更新 = on_插座UI更新;

	f_setOriginalPos({ 100, 100 });
	f_setMinSize({ 8, 8 });


	
	mf_开始拖拽 = f_插座准备拖动;
	mf_拖拽     = on_插座拖动;
	mf_结束拖拽 = f_插座结束拖动;

	mf_鼠标进入 = on_鼠标进入连接点;
	mf_鼠标离开 = on_鼠标离开连接点;

	m_ICO = "Light_Off_box_128px_582703_easyicon.net";
	m_颜色A = S_主题颜色::uic_节点插座;
	m_颜色B = S_主题颜色::uic_节点插座;
}

C_ui节点插座::~C_ui节点插座() {
	m_SocketData = 0;
}








static vec2 g节点鼠标局部位置 = { 0,0 };



static E_事件是否传递 on_节点准备拖动(struct C_Widget* 部件, const S_鼠标& 鼠标, S_拖放数据& data) {
	C_节点面板* 节点 = dynamic_cast<C_节点面板*>(部件->m_父部件);
	auto* 节点视口 = dynamic_cast<C_节点视口*>(节点->m_父部件);
	//std::cout << 手柄->m_Pos.x << " " << value.y << std::endl;
	
	if(C_节点面板::m_移动面板 || !S_框架::g_开启节点移动) return E_事件是否传递::e_事件传递_继续;
	
	g节点鼠标局部位置 = f_widget_get鼠标局部位置(鼠标.gPos, 节点视口);



	if (C_节点操作_移动节点::g当前移动操作 == nullptr) {
		std::vector<C_节点基类*> selectNode = { 节点->m_NodeData };
		vec2 标准坐标 = f_NodePanel_get标准坐标(g节点鼠标局部位置, 节点视口->m_扩展视口属性);
		C_节点操作_移动节点::g当前移动操作 = new C_节点操作_移动节点(selectNode, 标准坐标);

		g插座拖放数据.发起的节点树 = 节点视口;
		g插座拖放数据.发起的节点 = 节点;

		data.m_Type = E_自定义拖放数据类型::e_拖放_节点;
		data.m_Next = &g插座拖放数据;

		C_节点面板::m_移动面板 = true;
	}

	return E_事件是否传递::e_事件传递_继续;
}

static E_事件是否传递 on_节点拖动(C_Widget* self, const S_鼠标& 鼠标, S_拖放数据& data) {
	auto* 节点面板 = dynamic_cast<C_节点面板*>(self->m_父部件);
	if(!S_框架::g_开启节点移动) return E_事件是否传递::e_事件传递_继续;

	if(!节点面板->m_节点当前所在视口 || !C_节点面板::m_移动面板) return E_事件是否传递::e_事件传递_终止;

	vec2 pos = f_widget_get鼠标局部位置(鼠标.gPos, 节点面板->m_父部件);
	if (C_节点操作_移动节点::g当前移动操作) {
		
		C_节点操作_移动节点::g当前移动操作->f_移动(f_NodePanel_get标准坐标(pos, 节点面板->m_父部件));

	}
	else {
		return E_事件是否传递::e_事件传递_终止;
	}


	vec2 当前中心坐标 = f_NodePlane_get中心坐标(节点面板);

	float32 纵向最小 = 10000000;
	float32 横向最小 = 10000000;
	int32 纵向ID = -1;
	int32 横向ID = -1;


	C_节点视口& view = *((C_节点视口*)节点面板->m_节点当前所在视口);
	auto& e = 节点面板->m_节点当前所在视口->f_get更新部件();
	for (uint32 i = 0; i < e.m_Num; ++i) {
		if (e.m_W[i] == 节点面板) continue;

		vec2 cc = f_NodePlane_get中心坐标((C_节点面板*)e.m_W[i]);
		vec2 dir = cc - 当前中心坐标;
		float32 距离 = vec_len(dir);
		
		float32 dt = (1-fabs(vec_dot(vec_normalize(dir), { 0,1 }))) * 距离;
		if (dt < 纵向最小) {
			纵向最小 = dt;
			纵向ID = i;
		}

		dt = (1-fabs(vec_dot(vec_normalize(dir), { 1,0 }))) * 距离;
		if (dt < 横向最小) {
			横向最小 = dt;
			横向ID = i;
		}
	}


	bool 关闭对齐线 = true;

	vec2 中心偏移 = f_NodePlane_get中心偏移(节点面板);

	pos = 节点面板->m_Pos;
	uint32 IDOffset = 0;
	if (纵向ID != -1 && fabs(pos.x - e.m_W[纵向ID]->m_Pos.x) < 10) {
		pos.x = e.m_W[纵向ID]->m_Pos.x;

		vec2 S位置 = (pos - view.m_扩展视口属性->m_中心) / view.m_扩展视口属性->m_比例.x;
		vec2 E位置 = (vec2{ pos.x, e.m_W[纵向ID]->m_Pos.y } - view.m_扩展视口属性->m_中心) / view.m_扩展视口属性->m_比例.x;

		S位置 += 中心偏移;
		E位置 += f_NodePlane_get中心偏移((C_节点面板*)e.m_W[纵向ID]);

		view.f_绘制对齐线(E位置, S位置, { 50,128,80,200 }, IDOffset);
		关闭对齐线 = false;
		++IDOffset;
	}

	if (横向ID != -1 && fabs(pos.y - e.m_W[横向ID]->m_Pos.y) < 10) {
		pos.y = e.m_W[横向ID]->m_Pos.y;

		vec2 S位置 = (pos - view.m_扩展视口属性->m_中心) / view.m_扩展视口属性->m_比例.x;
		vec2 E位置 = (vec2{ e.m_W[横向ID]->m_Pos.x, pos.y } - view.m_扩展视口属性->m_中心) / view.m_扩展视口属性->m_比例.x;

		S位置 += 中心偏移;
		E位置 += f_NodePlane_get中心偏移((C_节点面板*)e.m_W[横向ID]);

		view.f_绘制对齐线(E位置, S位置, { 50,128,80,200 }, IDOffset);
		关闭对齐线 = false;
	}


	if (关闭对齐线) {
		view.f_连接线线尾拖动结束();
	}

	f_NodePlane_鼠标设置节点坐标(节点面板, pos);
	
	return E_事件是否传递::e_事件传递_终止;
}

static bool on_节点结束拖放(C_Widget* 节点内部面板, C_Widget* 拾取的部件, S_拖放数据& data) {
	if (!S_框架::g_开启节点移动) return false;

	C_节点面板* 节点 = dynamic_cast<C_节点面板*>(节点内部面板->m_父部件);
	auto* 节点视口 = dynamic_cast<C_节点视口*>(节点->m_父部件);

	if (C_节点操作_移动节点::g当前移动操作) {
		for (auto& e : C_节点操作_移动节点::g当前移动操作->m_Nodes) {
			e.m_移动后坐标 = e.m_node->m_坐标;
		}
		//g当前移动面板操作->m_移动后坐标 = 节点->m_Pos;
		C_节点操作_移动节点::g当前移动操作 = nullptr;
	}

	节点视口->f_连接线线尾拖动结束();
	f_widget_单个部件裁剪(节点, 节点视口->m_裁剪大小, 节点视口->m_GlobalLoc);
	节点->m_绘制属性更新 = true;

	C_节点面板::m_移动面板 = false;
	return true;
}






static void f_节点面板布局(C_Widget* self, C_Widget** w, uint32 num) {
	C_节点面板* 节点面板 = dynamic_cast<C_节点面板*>(self);
	f_NodePlane_更新布局(节点面板);
	
	
	C_节点视口* view = ((C_节点视口*)节点面板->m_节点当前所在视口);
	switch (view->m_节点树后端->m_布局方向) {
	case E_方向::e_纵向: {
		节点面板->f_插座横向变换更新();
		break;
	}
	case E_方向::e_横向: {
		节点面板->f_插座纵向排列布局更新();
		break;
	}
	}

}

bool on_内部面板按钮鼠标进入(C_Widget* self, const S_鼠标& 鼠标) {
	C_节点面板* Node = dynamic_cast<C_节点面板*>(self->m_父部件);
	Node->m_拖拽到其他视口按钮->m_颜色A = Node->m_拖拽到其他视口按钮->m_颜色B + S_RGBA8UI{ 30, 30, 50, 0 };
	Node->m_绘制属性更新 = true;

	S_框架::g_ui顶层画布->m_绘制属性更新 = true;
	S_框架::g_ui顶层画布->mf_DrawFun = on_节点全屏链接线绘制;
	S_框架::g_ui顶层画布->mf_变换修改 = on_节点全屏链接线变换修改;
	S_框架::g_ui顶层画布->mf_鼠标移动 = on_节点全屏链接线鼠标移动;
	
	return true;
}

bool on_内部面板按钮鼠标离开(C_Widget* self, const S_鼠标& 鼠标) {
	C_节点面板* Node = dynamic_cast<C_节点面板*>(self->m_父部件);
	Node->m_拖拽到其他视口按钮->m_颜色A = Node->m_拖拽到其他视口按钮->m_颜色B;
	Node->m_绘制属性更新 = true;

	return true;
}


static bool on_节点钉住(C_Widget* self, const E_鼠标按钮& 按钮) {
	C_节点面板* Node = dynamic_cast<C_节点面板*>(self->m_父部件);
	C_节点面板* 已有面板 = f_global_get钉住节点();
	if (已有面板) {
		已有面板->m_焦点颜色 = S_主题颜色::uic_节点面板焦点;
	}
	if (已有面板 != Node) {
		f_global_set钉住节点(Node);
		Node->m_焦点颜色 = S_主题颜色::uic_节点面板焦点 + S_RGBA8UI{50,80,200,0};
	}
	else {
		f_global_set钉住节点(nullptr);
	}

	
	self->m_父部件->m_绘制属性更新 = true;
	return true;
}


C_节点面板::C_节点面板(C_节点基类* nd, S_UI创建环境& ctx, E_节点区类型 区类型) : m_区(区类型), m_NodeData(nd) {
	debug_g_ctx = &ctx;
	m_NodeData->m_包含在多个视口的UI部件.insert(this);
	
	m_是否已弃用 = false;
	m_绘制排列方式 = E_方向::e_纵向;
	m_同子集节点树关联UI部件 = nullptr;
	m_节点当前所在视口 = nullptr;
	m_图元 = S_Widget预设图元::m_圆角矩形;

	//mf_变换修改 = f_set节点面板变换修改;
	m_扩展绘制			= 0;
	m_3D视口更新		= 0;
	m_属性面板参数构建	= 0;
	m_更新时间 = 0;

	mf_布局Fun = f_节点面板布局;
	//mf_DrawFun = on_节点面板绘制;
	//mf_变换修改 = on_节点面板变换修改;

	m_颜色A = S_UI主题::uic_节点面板;
	m_颜色B = S_UI主题::uic_节点面板高亮;
	m_颜色C = S_UI主题::uic_节点焦点;
	m_焦点颜色 = S_主题颜色::uic_节点面板焦点;

	m_NodeData->m_颜色 = S_UI主题::uic_节点面板;


	m_子部件裁剪使用父裁剪区域 = true;

	m_节点面板宽度 = 100;
	m_拾取区域大小.x = m_节点面板宽度;
	m_拾取区域大小.y = m_拾取区域大小.x * 0.7;
	f_setMinSize(m_拾取区域大小);
	

	m_高比例 = 0.25;
	m_拾取区域大小.y = m_拾取区域大小.x * m_高比例;

	m_内部面板 = new C_Widget();
	vec2 loc{ float32(g左边插座大小.x), float32(((m_拾取区域大小.x * 0.7f) * 0.5f) - m_拾取区域大小.y * 0.5)};
	vec2 内部面板大小 = { m_拾取区域大小.x - g左边插座大小.x, m_拾取区域大小.y };
	m_内部面板->f_setPos(loc);
	m_内部面板->f_setOriginalPos(loc);
	m_内部面板->f_setMinSize(内部面板大小);
	//m_内部面板->mf_鼠标按键点击 = on_节点面板鼠标单击;
	m_内部面板->mf_拖拽		= on_节点拖动;
	m_内部面板->mf_开始拖拽 = on_节点准备拖动;
	m_内部面板->mf_结束拖拽 = on_节点结束拖放;

	m_拖拽到其他视口按钮 = new C_Widget();
	m_拖拽到其他视口按钮->f_setOriginalPos({ m_拾取区域大小.x - 10, loc.y });
	m_拖拽到其他视口按钮->f_setMinSize({ 10, m_拾取区域大小.y });
	m_拖拽到其他视口按钮->mf_鼠标进入 = on_内部面板按钮鼠标进入;
	m_拖拽到其他视口按钮->mf_鼠标离开 = on_内部面板按钮鼠标离开;
	m_拖拽到其他视口按钮->m_颜色A = S_UI主题::uic_节点面板 + S_RGBA8UI{ 10, 10, 20, 255 };
	m_拖拽到其他视口按钮->m_颜色B = S_UI主题::uic_节点面板 + S_RGBA8UI{ 10, 10, 20, 255 };
	m_拖拽到其他视口按钮->mf_开始拖拽 = on_节点子集按钮准备拖动;
	m_拖拽到其他视口按钮->mf_拖拽 = on_节点子集按钮拖动;
	m_拖拽到其他视口按钮->mf_结束拖拽 = f_节点子集按钮结束拖动;

	m_独显按钮 = new C_Widget();
	m_独显按钮->f_setOriginalPos(loc);
	m_独显按钮->f_setMinSize({ 10, m_拾取区域大小.y });
	m_独显按钮->m_颜色A = S_UI主题::uic_节点面板 + S_RGBA8UI{ 10, 10, 10, 255 };
	m_独显按钮->m_颜色B = S_UI主题::uic_节点面板 + S_RGBA8UI{ 10, 10, 10, 255 };
	m_独显按钮->mf_鼠标按键点击 = on_节点钉住;

	f_添加子组件(m_内部面板);
	f_添加子组件(m_拖拽到其他视口按钮);
	f_添加子组件(m_独显按钮);



	S_鼠标双击键位映射* 鼠标键位 = f_widget_alloc_鼠标双击键位映射();
	鼠标键位->event = f_NodePlane_进入子集;
	鼠标键位->鼠标按键[0] = E_Input_鼠标按键::e_左键;
	鼠标键位->鼠标状态[0] = DEF_按键状态_按下;
	鼠标键位->发生组件 = this;
	f_ui_注册鼠标快捷键(this, (S_键位映射*)鼠标键位);

	/*S_鼠标键位映射* 鼠标键位 = f_widget_init_鼠标键位映射();
	鼠标键位->event = f_NodePlane_进入子集;
	鼠标键位->鼠标按键[0] = E_Input_鼠标按键::e_左键;
	鼠标键位->鼠标状态[0] = DEF_按键状态_按下;
	鼠标键位->发生组件 = this;
	f_ui_注册鼠标快捷键(this, (S_键位映射*)鼠标键位);*/

	m_背景GPU内存偏移 = 0;
	m_文字GPU内存偏移 = 0;
	m_链接线GPU内存偏移 = 0;
}

C_节点面板::~C_节点面板() {
}

void C_节点面板::f_addInSocket(C_插座基类* socketData, int16 offset) {
	C_ui节点插座* ui_socket = new C_ui节点插座(this, socketData);
	f_添加子组件(ui_socket, offset);

	//socketData->m_UI部件 = ui_socket;
	if (offset >= m_InSocket.size()) {
		m_InSocket.push_back(ui_socket);
	}
	else {
		m_InSocket.insert(m_InSocket.begin() + offset, ui_socket);
	}
	m_绘制属性更新 = true;
}

void C_节点面板::f_addOutSocket(C_插座基类* socketData, int16 offset) {
	C_ui节点插座* ui_socket = new C_ui节点插座(this, socketData);
	f_添加子组件(ui_socket, offset);

	if (offset >= m_OutSocket.size()) {
		m_OutSocket.push_back(ui_socket);
	}
	else {
		m_OutSocket.insert(m_OutSocket.begin() + offset, ui_socket);
	}
	
	m_绘制属性更新 = true;
}


void C_节点面板::f_removeInSocket(int16 offset) {
	if (m_InSocket.size() <= 1) return;

	std::vector<C_Widget*> 要销毁的插座组件;
	if (offset >= m_InSocket.size()) {
		要销毁的插座组件.emplace_back(m_InSocket.back());
		m_InSocket.pop_back();
	}
	else {
		m_InSocket[offset]->m_SocketData = nullptr;
		要销毁的插座组件.emplace_back(m_InSocket[offset]);
		m_InSocket.erase(m_InSocket.begin() + offset);
	}

	f_widget_remove子部件(this, 要销毁的插座组件, true);
	m_绘制属性更新 = true;
}

void C_节点面板::f_removeOutSocket(int16 offset) {
	if (m_OutSocket.size() <= 1) return;

	std::vector<C_Widget*> 要销毁的插座组件;
	if (offset >= m_OutSocket.size()) {
		要销毁的插座组件.emplace_back(m_OutSocket.back());
		m_OutSocket.pop_back();
	}
	else {
		m_OutSocket[offset]->m_SocketData = nullptr;
		要销毁的插座组件.emplace_back(m_OutSocket[offset]);
		m_OutSocket.erase(m_OutSocket.begin() + offset);
	}

	f_widget_remove子部件(this, 要销毁的插座组件, true);
	m_绘制属性更新 = true;
}

void C_节点面板::f_releaseAllSocket() {
	//for (auto& socket : m_InSocket) {
	//	socket->m_SocketData = nullptr;
	//}
	std::vector<C_Widget*> ws;
	ws.assign(m_InSocket.begin(), m_InSocket.end());
	f_widget_remove子部件(this, ws, true);
	ws.assign(m_OutSocket.begin(), m_OutSocket.end());
	f_widget_remove子部件(this, ws, true);


	m_InSocket.clear();
	m_OutSocket.clear();
	m_绘制属性更新 = true;
}




C_ui节点插座* C_节点面板::f_getInSocket(uint16 id) {
	return m_InSocket[id];
}

C_ui节点插座* C_节点面板::f_getOutSocket(uint16 id) {
	return m_OutSocket[id];
}

ivec4 C_节点面板::f_get插座GPU参数() {
	return ivec4{ int32(m_NodeData->f_get输入插座Num()), 0, int32(m_NodeData->f_get输出插座Num()), 0 };
}

void C_节点面板::f_插座横向变换更新() {
	uvec2 dim = { uint32(m_InSocket.size()), uint32(m_OutSocket.size()) };
	
	float32 offset = 0.0;
	float32 多链接插座宽度 = 0;
	

	vec2 面板拾取区域大小 = m_内部面板->f_getOriginalSize();
	vec2 面板拾取区域偏移 = m_内部面板->f_getOriginalPos();

	//float32 缩减宽度 = (g_节点面板宽度 - g左边插座大小.x) * 0.85;
	float32 缩减宽度 = (面板拾取区域大小.x - g左边插座大小.x) * 0.85;

	uint16 多输入插座数量 = m_NodeData->f_get多输入插座数量();
	uint16 单链接插座数量 = 0;
	if (多输入插座数量) {
		单链接插座数量 = (dim.x - 1 - 多输入插座数量);
		if (单链接插座数量 > 0) {
			offset = (缩减宽度 * 0.5) / 单链接插座数量;
		}

		多链接插座宽度 = (缩减宽度 - ((单链接插座数量) * offset)) / 多输入插座数量;
	}
	else {
		offset = 缩减宽度 / (dim.x-1);
	}
	
	

	//vec2 socketOriginalSize = { offset, m_节点面板宽度 * 0.4f };
	//vec2 socketSize = socketOriginalSize * m_Scale.x;
	//
	//float32 x = (m_节点面板宽度 - g左边插座大小.x - 缩减宽度) * 0.5 + g左边插座大小.x;
	//float32 y = f_getOriginalSize().y * 0.5 - (m_节点面板宽度 * m_高比例) * 0.5 - socketOriginalSize.y;


	vec2 socketOriginalSize = { offset, 面板拾取区域大小.y * 0.4f };
	//vec2 socketSize = socketOriginalSize * m_Scale.x;

	float32 x = 面板拾取区域偏移.x + (面板拾取区域大小.x - 缩减宽度) * 0.5;
	float32 y = 面板拾取区域偏移.y - socketOriginalSize.y;


	vec2 loc = { x, y};
	int32 i = 0;
	for (auto& s : m_InSocket) {
		if (i) {
			bool 单链接 = s->m_SocketData->f_is单链接();
			if (单链接) {
				socketOriginalSize.x = offset;
			}
			else {
				socketOriginalSize.x = 多链接插座宽度;
			}

			s->f_setOriginalPos(loc);
			s->f_setPos(loc * m_Scale.x);

			s->f_setOriginalSize(socketOriginalSize);
			s->f_setSize(socketOriginalSize * m_Scale.x);

			if (单链接) {
				loc.x += offset;
			}
			else {
				loc.x += 多链接插座宽度;
			}

		}
		else {
			loc.x = 0;
			loc.y = f_getOriginalSize().y * 0.5 - g左边插座大小.y - 2;
			vec2 size = { m_内部面板->m_Size.y * 0.3f, m_内部面板->m_Size.y * 0.3f };
			
			s->f_setOriginalPos(loc);
			s->f_setPos(loc * m_Scale.x);

			s->f_setOriginalSize(g左边插座大小);
			s->f_setSize(g左边插座大小 * m_Scale.x);

			loc = { x, y };
		}
		
		++i;
	}



	if (dim.y > 1) {
		offset = DEF_Max(m_节点面板宽度 * 0.8 / (dim.y), C_节点面板::m_链接点直径);
	}
	else {
		offset = C_节点面板::m_链接点直径;
	}
	
	socketOriginalSize = { offset, m_节点面板宽度 * 0.4f };
	//x = (m_节点面板宽度 - g左边插座大小.x - ((dim.y-1) * offset)) * 0.5 + g左边插座大小.x;
	//y = f_getOriginalSize().y * 0.5 + (m_节点面板宽度 * m_高比例) * 0.5;

	x = 面板拾取区域偏移.x + (面板拾取区域大小.x - ((dim.y - 1) * offset)) * 0.5;
	y = 面板拾取区域偏移.y + 面板拾取区域大小.y;


	i = 0;
	for (auto& s : m_OutSocket) {
		vec2 loc;

		if (i) {
			loc = { offset * (i-1) + x, y };
			
			s->f_setOriginalPos(loc);
			s->f_setOriginalSize(socketOriginalSize);

			s->f_setPos(loc * m_Scale.x);
			s->f_setSize(socketOriginalSize * m_Scale.x);

		}
		else {
			vec2 size = { m_内部面板->m_Size.y * 0.3f, m_内部面板->m_Size.y * 0.3f };
			
			//loc.x = -g左边插座大小.x;
			loc.x = 0;
			loc.y = f_getOriginalSize().y * 0.5 + 2;

			s->f_setOriginalPos(loc);
			s->f_setOriginalSize(g左边插座大小);

			s->f_setPos(loc * m_Scale.x);
			s->f_setSize(g左边插座大小 * m_Scale.x);
		}
		
		++i;
	}
}

void C_节点面板::f_插座纵向排列布局更新() {
	uvec2 dim = { uint32(m_InSocket.size()), uint32(m_OutSocket.size()) };

	float32 offset = g纵向插座大小.y;
	
	

	vec2 面板大小 = m_内部面板->f_getOriginalSize();
	vec2 边框大小 = f_getOriginalSize();
	
	if (m_NodeData->m_Type == E_节点类型::e_节点Type_Reroute) {
		auto* s0 = m_InSocket[0];

		vec2 loc{ float32(m_内部面板->f_getOriginalPos().x + m_内部面板->f_getOriginalSize().x * 0.5 - g左边插座大小.y * 0.5), float32(0)};
		s0->f_setOriginalPos(loc);
		s0->f_setPos(loc * m_Scale.x);
		s0->f_setOriginalSize({ g左边插座大小.y, g左边插座大小.x });
		s0->f_setSize(vec2{ g左边插座大小.y, g左边插座大小.x } *m_Scale.x);


		s0 = m_OutSocket[0];
		vec2 size = { g左边插座大小.y, g左边插座大小.x };
		//loc.x = 面板大小.x * 0.5 - g左边插座大小.y * 0.5;
		loc.y = m_内部面板->f_getOriginalPos().y + m_内部面板->f_getOriginalSize().y;
		s0 = m_OutSocket[0];
		s0->f_setOriginalPos(loc);
		s0->f_setOriginalSize(size);
		s0->f_setPos(loc * m_Scale.x);
		s0->f_setSize(size * m_Scale.x);


		
		vec2 socketOriginalSize = { g插座宽度, 0 };
		loc.x = 0;
		loc.y = m_内部面板->f_getOriginalPos().y;
		loc.y += m_内部面板->f_getOriginalSize().y * 0.5f;
		loc.y -= g纵向插座大小.y*0.5f;
		s0 = m_InSocket[1];
		s0->f_setOriginalPos(loc);
		s0->f_setPos(loc * m_Scale.x);

		s0->f_setOriginalSize(g纵向插座大小);
		s0->f_setSize(g纵向插座大小 * m_Scale.x);


		s0 = m_OutSocket[1];
		loc.x = m_内部面板->f_getOriginalPos().x + m_内部面板->f_getOriginalSize().x;
		s0->f_setOriginalPos(loc);
		s0->f_setPos(loc * m_Scale.x);

		s0->f_setOriginalSize(g纵向插座大小);
		s0->f_setSize(g纵向插座大小 * m_Scale.x);

		return;
	}
	else {
		面板大小 = m_内部面板->f_getOriginalSize();
	}


	面板大小.y -= S_UI主题::ui_面板圆角半径;
	float32 多链接插座高度 = 0;

	uint16 多输入插座数量 = m_NodeData->f_get多输入插座数量();
	uint16 单链接插座数量 = 0;
	if (多输入插座数量) {
		单链接插座数量 = ((dim.x + dim.y) - 2 - 多输入插座数量);
		if (单链接插座数量 > 0) {
			offset = ((面板大小.y - g内部按钮大小) * 0.5) / 单链接插座数量;
		}

		多链接插座高度 = (面板大小.y - g内部按钮大小 - ((单链接插座数量) * offset)) / 多输入插座数量;
	}
	else {
		offset = g纵向插座大小.y;
	}



	float32 输出插座偏移 = 0;
	{
		vec2 socketOriginalSize = { g插座宽度, offset };
		//vec2 socketSize = socketOriginalSize * m_Scale.x;
		float32 x = 0;
		float32 y = g左边插座大小.x + g内部按钮大小;
		

		vec2 loc = { x, y};
		int32 i = 0;
		for (auto& s : m_InSocket) {
			if (i) {
				输出插座偏移 = loc.y;

				bool 单链接 = s->m_SocketData->f_is单链接();
				if (单链接) {
					socketOriginalSize.y = offset;
				}
				else {
					socketOriginalSize.y = 多链接插座高度;
				}

				s->f_setOriginalPos(loc);
				s->f_setPos(loc * m_Scale.x);

				s->f_setOriginalSize(socketOriginalSize);
				s->f_setSize(socketOriginalSize * m_Scale.x);

				if (单链接) {
					loc.y += offset;
				}
				else {
					loc.y += 多链接插座高度;
				}
			}
			else {
				loc.x = m_节点面板宽度 * 0.5 - g左边插座大小.y * 0.5;
				loc.y = 0;
				s->f_setOriginalPos(loc);
				s->f_setPos(loc * m_Scale.x);

				s->f_setOriginalSize({g左边插座大小.y, g左边插座大小.x});
				s->f_setSize(vec2{g左边插座大小.y, g左边插座大小.x} * m_Scale.x);
				loc = { 0, y };
			}
			++i;
		}
	}
	

	{
		vec2 socketOriginalSize = { g插座宽度, offset };
		//socketOriginalSize = { offset, m_节点面板宽度 * 0.4f };
		float32 x = 边框大小.x - g内部按钮大小;
		float32 y = 输出插座偏移;

		int32 i = 0;
		for (auto& s : m_OutSocket) {
			vec2 loc;

			if (i) {
				loc = { x, y + i*offset };

				s->f_setOriginalPos(loc);
				s->f_setOriginalSize(socketOriginalSize);

				s->f_setPos(loc * m_Scale.x);
				s->f_setSize(socketOriginalSize * m_Scale.x);
			}
			else {
				vec2 size = {g左边插座大小.y, g左边插座大小.x};
				//loc.x = -g左边插座大小.x;
				loc.x = 边框大小.x * 0.5 - g左边插座大小.y*0.5;
				loc.y = 边框大小.y - g左边插座大小.x;

				s->f_setOriginalPos(loc);
				s->f_setOriginalSize(size);

				s->f_setPos(loc * m_Scale.x);
				s->f_setSize(size * m_Scale.x);
			}
			++i;
		}
	}
}



void C_节点面板::f_从后端重建插座() {
	int16 num = m_InSocket.size();

	int16 inNum = m_NodeData->f_get输入插座Num();
	num -= inNum;
	for (uint16 i = 1; i < inNum; ++i) {
		auto* inNode = m_NodeData->f_get输入插座(i);

		if (i > num) {
			f_addInSocket(inNode);
		}
		else {
			m_InSocket[i]->m_SocketData = inNode;
		}
	}

	if (num > 0) {
		for (uint16 i = 0; i < num; ++i) f_removeInSocket();
	}



	num = m_OutSocket.size();

	int16 outNum = m_NodeData->f_get输出插座Num();
	num -= outNum;
	for (uint16 i = 1; i < outNum; ++i) {
		auto* outNode = m_NodeData->f_get输出插座(i);

		if (i > num) {
			f_addOutSocket(outNode);
		}
		else {
			m_OutSocket[i]->m_SocketData = outNode;
		}
	}

	if (num > 0) {
		for (uint16 i = 0; i < num; ++i) f_removeOutSocket();
	}

}




static vec2 f_输入插座中心坐标(C_节点面板* plane, C_插座基类* socket, E_插座方向 方向) {
	vec2 插座大小 = socket->m_UI部件->f_getOriginalSize();
	插座大小.x /= 2;
	插座大小.y = 0;

	插座大小.x += socket->m_UI部件->f_getOriginalPos().x;
	插座大小.y += socket->m_UI部件->f_getOriginalPos().y;
	if (方向 == E_插座方向::e_插座Type_输入) {
		插座大小.y = socket->m_UI部件->f_getOriginalSize().y - C_节点面板::m_链接点直径;
	}
	else {
		插座大小.y += C_节点面板::m_链接点直径;
	}
	//插座大小.y += C_节点面板::m_链接点直径;
	//return 插座大小;
	return 插座大小 + socket->m_UI部件->m_父部件->f_getOriginalPos();
}





S_Line C_节点面板::f_计算横向排列插座连接线坐标(S_NodeLink* link, uint16 接入数量, uint16 offset, uint8 插座类型) {
	S_Line line;
	const auto* socket_out = ((C_ui节点插座*)(link->m_插座out->m_UI部件));
	if (!socket_out) return {};

	C_节点面板* 链接到的节点面板 = socket_out->m_NodePlane;
	line.start = socket_out->f_getOriginalPos() + 链接到的节点面板->f_getOriginalPos();
	
	switch (插座类型) {
	case E_插座方向::e_插座Type_输入:
		line.start.x += socket_out->f_getOriginalSize().x * 0.5;
		line.start.y += 6;
		break;
	default:
		line.start.x += socket_out->f_getOriginalSize().x * 0.5f;
		line.start.y += g插座大小.y;
		break;
	}
	

	const auto* socket = ((C_ui节点插座*)link->m_插座in->m_UI部件);
	if (!socket) return {};
	
	line.end = socket->f_getOriginalPos() + f_getOriginalPos();
	float32 插座宽度 = socket->f_getOriginalSize().x * 0.9f;
	

	switch (插座类型) {
	case E_插座方向::e_插座Type_输入:
		line.end += socket->f_getOriginalSize() * 0.5;
		break;
	default:
		line.end.x += 插座宽度 / (接入数量 + 1) * offset;
		line.end.x += (socket->f_getOriginalSize().x - 插座宽度) * 0.5;
		line.end.y += socket->f_getOriginalSize().y - g插座大小.y;
		break;
	}
	

	return line;
}

S_Line C_节点面板::f_计算纵向排列插座连接线坐标(S_NodeLink* link, uint16 接入数量, uint16 offset, uint8 插座类型) {
	S_Line line;
	const auto* socket_out = ((C_ui节点插座*)(link->m_插座out->m_UI部件));
	if (!socket_out) return {};

	C_节点面板* 链接到的节点面板 = socket_out->m_NodePlane;
	line.start = socket_out->f_getOriginalPos() + 链接到的节点面板->f_getOriginalPos();

	switch (插座类型) {
	case 0:
		line.start += socket_out->f_getOriginalSize().y * 0.5;
		break;
	default:
		line.start += socket_out->f_getOriginalSize() * 0.5f;
		break;
	}


	const auto* socket = ((C_ui节点插座*)link->m_插座in->m_UI部件);
	if (!socket) return {};

	line.end = socket->f_getOriginalPos() + f_getOriginalPos();
	
	vec2 size = socket->f_getOriginalSize();
	switch (插座类型) {
	case 0:
		line.end += socket->f_getOriginalSize().x * 0.5;
		break;
	default:
		size.y = ((size.y-4) / 接入数量);
		line.end.x += size.x * 0.5f;
		line.end.y += size.y * offset - size.y*0.5;
		break;
	}

	return line;
}


void C_节点面板::f_动态添加插座(C_插座基类* 输入插座) {
	//int32 loc = m_NodeData->f_get输入插座Loc(输入插座);

	std::vector<S_添加的插座> 删除的插座;
	C_插座基类* 新后端插座 = m_NodeData->f_动态添加插座(输入插座->f_get方向(), 删除的插座);

	for (auto& e : 删除的插座) {
		if (e.m_插座->f_get方向() == E_插座方向::e_插座Type_输入) {
			f_addInSocket(e.m_插座, e.m_插座后端位置);
		}
		else {
			f_addOutSocket(e.m_插座, e.m_插座后端位置);
		}
	}
	
}

void C_节点面板::f_动态删除插座() {
	//int32 loc = m_NodeData->f_get输入插座Loc(输入插座);
	std::vector<S_删除的插座> 删除的插座;
	int32 loc = m_NodeData->f_动态删除插座(E_插座方向::e_插座Type_输入, 删除的插座);

	for (auto& e : 删除的插座) {
		if (e.m_方向 == E_插座方向::e_插座Type_输入) {
			f_removeInSocket(e.m_插座后端位置);
		}
		else {
			f_removeOutSocket(e.m_插座后端位置);
		}
	}
	if (loc >= 0) {
		
	}
}


std::vector<C_节点面板*> C_节点面板::f_切断链接(vec2* lines, uint32 num) {
	if (!num) return {};

	uint32 inNum = m_InSocket.size();
	C_节点视口* view = (C_节点视口*)m_父部件;

	//std::vector<S_NodeLink*> 要断开的链接线;
	std::vector<S_链接线记录>	要断开的链接线;
	std::vector<C_节点面板*>	断开的节点;

	for (uint32 socketID = 0; socketID < inNum; ++socketID) {
		const auto linkLines = m_InSocket[socketID]->m_SocketData->f_getLinkLines();

		S_2D图元顶点* 图元顶点 = S_UI创建环境::m_预设图元顶点.data();

		

		//迭代梅根连接线
		uint16 k = 1;
		uint16 socketNum = linkLines.size();
		for (auto link : linkLines) {
			S_Line 线坐标;

			uint32 r;
			uint32 i;
			switch (view->m_节点树后端->m_布局方向) {
			case E_方向::e_纵向: 
				线坐标 = f_计算横向排列插座连接线坐标(link, socketNum, k, socketID); 

				if (socketID) {
					i = S_UI创建环境::m_图元ID.m_竖向圆角连接线.x;
					r = S_UI创建环境::m_图元ID.m_竖向圆角连接线.y - 1;
				}
				else {
					if (线坐标.end.x >= 线坐标.start.x) {
						i = S_UI创建环境::m_图元ID.m_生成L形下拐角连接线.x;
						r = S_UI创建环境::m_图元ID.m_生成L形下拐角连接线.y - 1;
					}
					else {
						i = S_UI创建环境::m_图元ID.m_生成L形上拐角连接线.x;
						r = S_UI创建环境::m_图元ID.m_生成L形上拐角连接线.y - 1;
					}
				}
				break;
			case E_方向::e_横向: 
				线坐标 = f_计算纵向排列插座连接线坐标(link, socketNum, k, socketID);
				if (socketID) {
					i = S_UI创建环境::m_图元ID.m_横向圆角连接线.x;
					r = S_UI创建环境::m_图元ID.m_横向圆角连接线.y - 1;
				}
				else {
					if (线坐标.end.x >= 线坐标.start.x) {
						i = S_UI创建环境::m_图元ID.m_竖向圆角连接线.x;
						r = S_UI创建环境::m_图元ID.m_竖向圆角连接线.y - 1;
					}
					else {
						i = S_UI创建环境::m_图元ID.m_竖向圆角连接线.x;
						r = S_UI创建环境::m_图元ID.m_竖向圆角连接线.y - 1;
					}
				}
				break;
			}

			vec2 大小 = 线坐标.end - 线坐标.start;
			//vec2 大小 = 线坐标.start - 线坐标.end;
			mat3X2 mat;
			mat.row0 = 线坐标.start;
			mat.row1 = 大小;
			mat.row2 = { DEF_Min(fabs(大小.x), fabs(大小.y)) * 0.7f, 0 };

			for (; i < r; ++i) {
				S_Line line;
				line.start = 图元顶点[i].coord;
				line.end = 图元顶点[i+1].coord;
				
				line.start = mat.row0 + ((line.start * mat.row2.x) + ((mat.row1 - mat.row2.x) * 图元顶点[i].weights));
				line.end = mat.row0 + ((line.end * mat.row2.x) + ((mat.row1 - mat.row2.x) * 图元顶点[i+1].weights));
				
				int32 id = f_graph_线段相交(line, lines, num);
				if (id >= 0) {
					cout << "剪切到了线:" << id << endl;
					uvec2 r_id = link->f_断开输出链接();
					
					断开的节点.push_back(this);
					要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
					m_绘制属性更新 = true;
					break;
				}
			}
		}
	}

	if (要断开的链接线.size()) C_节点操作_切断链接* op = new C_节点操作_切断链接(要断开的链接线, nullptr);
	return 断开的节点;
}

std::vector<C_节点面板*> C_节点面板::f_切断园公切线链接(vec2* lines, uint32 num, float32 最大半径) {
	if (!num) return {};

	uint32 inNum = m_InSocket.size();
	C_节点视口* view = (C_节点视口*)m_父部件;

	std::vector<S_NodeLink*> 要断开的链接线;
	std::vector<C_节点面板*> 断开的节点;
	

	float32 PN;
	S_CurvePoint curve;
	curve.value = { 最大半径, 最大半径 };

	
	float a = M_PI / 180 * 4;

	for (uint32 socketID = 0; socketID < inNum; ++socketID) {
		const auto linkLines = m_InSocket[socketID]->m_SocketData->f_getLinkLines();

		//迭代梅根连接线
		uint16 k = 1;
		uint16 socketNum = linkLines.size();
		for (auto link : linkLines) {
			
			vec2 v;
			vec2 头坐标;
			int32 id = -1;


			switch (view->m_节点树后端->m_布局方向) {
				case E_方向::e_纵向:
					if (socketID) {
						curve.Select_Type.y = DEF_LINKLINE_TYPE_CircleTangent_V;
					}
					else {
						curve.Select_Type.y = DEF_LINKLINE_TYPE_C;
					}
					break;
				case E_方向::e_横向:
					if (socketID) {
						curve.Select_Type.y = DEF_LINKLINE_TYPE_CircleTangent_H;
					}
					else {
						curve.Select_Type.y = DEF_LINKLINE_TYPE_CircleTangent_V;
					}
					break;
			}
			

			
			switch (curve.Select_Type.y) {
			case DEF_LINKLINE_TYPE_CircleTangent_V: {
				S_Line 线坐标 = f_计算横向排列插座连接线坐标(link, socketNum, k, socketID);

				curve.L_point = 线坐标.start;
				curve.R_point = 线坐标.end;
				vec2 size = curve.R_point - curve.L_point;
				float32 画圆角度 = f_glsl_Cal_CutCircleRadius(curve);

				vec2 end = curve.R_point;
				float Inv = curve.value.x;
				float angle = f_glsl_Cal_CutCircleNum(curve.L_point, end, int(curve.Select_Type.y), 画圆角度, Inv);


				PN = sign(size.x);
				uint 圆弧分割角度数量 = uint(degrees(angle) / 4);


				头坐标 = curve.L_point;
					
				for (int i = 0; i < 圆弧分割角度数量; ++i) {
					v.x = (-cos(a * i) * 画圆角度 + 画圆角度) * PN;
					v.y = sin(a * i) * 画圆角度;
					v += curve.L_point;


					id = f_graph_线段相交({ 头坐标 , v }, lines, num);
					头坐标 = v;
					if (id >= 0) {
						//cout << "剪切到了线:S " << id << " link:"<< link << "  socketID:" << socketID << " k:"<< k << endl;
						//link->f_断开输出链接();
						断开的节点.push_back(this);
						//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
						要断开的链接线.push_back(link);
						m_绘制属性更新 = true;
						break;
					}
				}
				if (id >= 0) break;


				for (int i = 0; i < 圆弧分割角度数量; ++i) {
					float index = 圆弧分割角度数量 - i - 1;
					v.x = (cos(a * index) * 画圆角度 - 画圆角度) * PN * Inv;
					v.y = sin(a * index) * -画圆角度;
					v += curve.R_point;


					id = f_graph_线段相交({ 头坐标 , v }, lines, num);
					头坐标 = v;
					if (id >= 0) {
						//cout << "剪切到了线:C " << id << " link:" << link << "  socketID:" << socketID << " k:" << k << endl;
						//link->f_断开输出链接();
						断开的节点.push_back(this);
						//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
						要断开的链接线.push_back(link);
						m_绘制属性更新 = true;
						break;
					}
				}
				if (id >= 0 || 圆弧分割角度数量) break;


				id = f_graph_线段相交({ 头坐标 , curve.R_point }, lines, num);
				if (id >= 0) {
					//cout << "剪切到了线:E " << id << "  num:" << 圆弧分割角度数量 << endl;
					//link->f_断开输出链接();
					断开的节点.push_back(this);
					//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
					要断开的链接线.push_back(link);
					m_绘制属性更新 = true;
					break;
				}


				break;
			}
			case DEF_LINKLINE_TYPE_CircleTangent_H: {
				S_Line 线坐标 = f_计算纵向排列插座连接线坐标(link, socketNum, k, socketID);

				curve.L_point = 线坐标.start;
				curve.R_point = 线坐标.end;
				vec2 size = curve.R_point - curve.L_point;
				float32 画圆角度 = f_glsl_Cal_CutCircleRadius(curve);

				vec2 end = curve.R_point;
				float Inv = curve.value.x;
				float angle = f_glsl_Cal_CutCircleNum(curve.L_point, end, int(curve.Select_Type.y), 画圆角度, Inv);



				PN = sign(size.x);
				uint 圆弧分割角度数量 = uint(degrees(angle) / 4);

				头坐标 = curve.L_point;
					
				for (int i = 0; i < 圆弧分割角度数量; ++i) {
					v.x = sin(a * i) * 画圆角度;
					v.y = (cos(a * i) * 画圆角度 - 画圆角度) * PN;

					v += curve.L_point;


					id = f_graph_线段相交({ 头坐标 , v }, lines, num);
					头坐标 = v;
					if (id >= 0) {
						断开的节点.push_back(this);
						//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
						要断开的链接线.push_back(link);
						m_绘制属性更新 = true;
						break;
					}
				}
				if (id >= 0) break;


				for (int i = 0; i < 圆弧分割角度数量; ++i) {
					float index = 圆弧分割角度数量 - i - 1;
					v.x = sin(a * index) * -画圆角度;
					v.y = (-cos(a * index) * 画圆角度 + 画圆角度) * PN * Inv;

					v += curve.R_point;


					id = f_graph_线段相交({ 头坐标 , v }, lines, num);
					头坐标 = v;
					if (id >= 0) {
						断开的节点.push_back(this);
						//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
						要断开的链接线.push_back(link);
						m_绘制属性更新 = true;
						break;
					}
				}
				if (id >= 0 || 圆弧分割角度数量) break;


				id = f_graph_线段相交({ 头坐标 , curve.R_point }, lines, num);
				if (id >= 0) {
					//cout << "剪切到了线:E " << id << "  num:" << 圆弧分割角度数量 << endl;
					//link->f_断开输出链接();
					断开的节点.push_back(this);
					//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
					要断开的链接线.push_back(link);
					m_绘制属性更新 = true;
				}
				break;
			}
			case DEF_LINKLINE_TYPE_C: {
				S_Line 线坐标 = f_计算纵向排列插座连接线坐标(link, socketNum, k, socketID);

				curve.L_point = 线坐标.start;
				curve.R_point = 线坐标.end;
				vec2 size = curve.R_point - curve.L_point;

				头坐标 = curve.L_point;
				v = curve.L_point;
				v.x = min(curve.L_point.x, curve.R_point.x) - 20;
				id = f_graph_线段相交({ 头坐标 , v }, lines, num);
				if (id >= 0) {
					断开的节点.push_back(this);
					//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
					要断开的链接线.push_back(link);
					m_绘制属性更新 = true;
					break;
				}
				头坐标 = v;
				v.y = curve.R_point.y;
				id = f_graph_线段相交({ 头坐标 , v }, lines, num);
				if (id >= 0) {
					断开的节点.push_back(this);
					//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
					要断开的链接线.push_back(link);
					m_绘制属性更新 = true;
					break;
				}
				头坐标 = v;
				v.x = curve.R_point.x;
				id = f_graph_线段相交({ 头坐标 , v }, lines, num);
				if (id >= 0) {
					断开的节点.push_back(this);
					//要断开的链接线.push_back(S_链接线记录{ link->m_插座out->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
					要断开的链接线.push_back(link);
					m_绘制属性更新 = true;
					break;
				}
			}
			}
			
			++k;
		}
	}


	std::vector<S_链接线记录> m_链接线链接插座ID;
	for (auto& link : 要断开的链接线) {
		auto r_id = link->f_断开输出链接();

		m_链接线链接插座ID.push_back(S_链接线记录{ link->m_插座in->f_getNode(), link->m_插座out->f_getNode(), link, r_id });
	}
	if (m_链接线链接插座ID.size()) C_节点操作_切断链接* op = new C_节点操作_切断链接(m_链接线链接插座ID, nullptr);
	return 断开的节点;
}

void C_节点面板::f_设置焦点(bool 是否开启焦点绘制) {
	m_NodeData->m_是否有焦点 = 是否开启焦点绘制;
	m_绘制属性更新 = true;
}





void f_NodePlane_数值更新刷新节点(C_Widget* w) {
	C_节点面板* plane = dynamic_cast<C_节点面板*>(w);

	plane->m_NodeData->f_set是否要更新(true);
}

void f_NodePlane_更新节点内部面板(C_Widget* self) {
	C_节点视口* view = (C_节点视口*)self->m_父部件;
	C_节点面板* 节点面板 = dynamic_cast<C_节点面板*>(self);

	auto& inSocket = 节点面板->f_getInSocket();
	auto& outSocket = 节点面板->f_getOutSocket();
	//vec2 wh = 内部面板大小 * 节点面板->m_Scale.x;
	uint32 插座数量 = DEF_Max(inSocket.size() + outSocket.size() - 2, 1);
	
	
	//static float32 内部按钮大小 = g插座宽度;
	switch (view->m_节点树后端->m_布局方向) {
		case E_方向::e_横向: {
			float32 heigth = 插座数量 * g纵向插座大小.y + g内部按钮大小 + S_UI主题::ui_面板圆角半径;

			vec2 loc;
			vec2 内部面板大小 = {};
			switch (节点面板->m_NodeData->m_Type) {
				case E_节点类型::e_节点Type_Reroute : {
					节点面板->m_拾取区域大小 = { 50 + g插座宽度 * 2, 50 };
					内部面板大小 = { 30, 30 };


					loc = { g插座宽度*1.2f, g左边插座大小.x };
					节点面板->m_内部面板->f_setOriginalPos(loc);
					节点面板->m_内部面板->f_setOriginalSize(内部面板大小);
					节点面板->m_内部面板->f_setPos(loc * 节点面板->m_Scale.x);
					节点面板->m_内部面板->f_setSize(内部面板大小 * 节点面板->m_Scale.x);


					节点面板->m_独显按钮->f_setOriginalPos({});
					节点面板->m_独显按钮->f_setOriginalSize({1});
					节点面板->m_独显按钮->f_setPos({});
					节点面板->m_独显按钮->f_setSize({1});


					节点面板->m_拖拽到其他视口按钮->f_setOriginalPos({});
					节点面板->m_拖拽到其他视口按钮->f_setOriginalSize({1});
					节点面板->m_拖拽到其他视口按钮->f_setPos({});
					节点面板->m_拖拽到其他视口按钮->f_setSize({1});
					break;
				}
				case E_节点类型::e_节点Type_框: {
					内部面板大小 = 节点面板->f_getOriginalSize();
			
					节点面板->m_内部面板->f_setOriginalPos({});
					节点面板->m_内部面板->f_setOriginalSize(内部面板大小);
					节点面板->m_内部面板->f_setPos({});
					节点面板->m_内部面板->f_setSize(内部面板大小 * 节点面板->m_Scale.x);

					节点面板->m_独显按钮->f_setOriginalPos({});
					节点面板->m_独显按钮->f_setOriginalSize({ 1 });
					
					节点面板->m_拖拽到其他视口按钮->f_setOriginalPos({});
					节点面板->m_拖拽到其他视口按钮->f_setOriginalSize({ 1 });
					
					节点面板->m_拾取区域大小 = 内部面板大小;
					break;
				}
				default: {
					节点面板->m_拾取区域大小.x = 节点面板->m_节点面板宽度;
					节点面板->m_拾取区域大小.y = heigth + g左边插座大小.x * 2;
					内部面板大小 = { 节点面板->m_拾取区域大小.x - g插座宽度 * 2, heigth };



					loc = { g插座宽度, g左边插座大小.x };
					节点面板->m_内部面板->f_setOriginalPos(loc);
					节点面板->m_内部面板->f_setOriginalSize(内部面板大小);
					节点面板->m_内部面板->f_setPos(loc * 节点面板->m_Scale.x);
					节点面板->m_内部面板->f_setSize(内部面板大小 * 节点面板->m_Scale.x);


					节点面板->m_独显按钮->f_setOriginalPos(loc);
					节点面板->m_独显按钮->f_setOriginalSize({ 内部面板大小.x * 0.5f, g内部按钮大小 });
					节点面板->m_独显按钮->f_setPos(节点面板->m_独显按钮->f_getOriginalPos() * 节点面板->m_Scale.x);
					节点面板->m_独显按钮->f_setSize(节点面板->m_独显按钮->f_getOriginalSize() * 节点面板->m_Scale.x);


					loc = { g插座宽度 + 内部面板大小.x * 0.5f,  g左边插座大小.x };
					节点面板->m_拖拽到其他视口按钮->f_setOriginalPos(loc);
					节点面板->m_拖拽到其他视口按钮->f_setOriginalSize({ 内部面板大小.x * 0.5f, g内部按钮大小 });
					节点面板->m_拖拽到其他视口按钮->f_setPos(节点面板->m_拖拽到其他视口按钮->f_getOriginalPos() * 节点面板->m_Scale.x);
					节点面板->m_拖拽到其他视口按钮->f_setSize(节点面板->m_拖拽到其他视口按钮->f_getOriginalSize() * 节点面板->m_Scale.x);
				}
			}
		

			节点面板->f_setOriginalSize(节点面板->m_拾取区域大小);
			节点面板->f_setSize(节点面板->m_拾取区域大小 * 节点面板->m_Scale.x);

			break;
		}

		default: {
			uint32 插座最大数量 = DEF_Max(inSocket.size(), outSocket.size());
			float32 width = inSocket.size() * 20;
			width = DEF_Max(width, outSocket.size() * 20);
			width = DEF_Max(width, 节点面板->m_节点面板宽度);



			vec2 loc;
			vec2 内部面板大小 = {};
			float32 内部操控按钮宽度;

			switch (节点面板->m_NodeData->m_Type) {
				case E_节点类型::e_节点Type_Reroute: {
			
					loc = { g左边插座大小.x, (60.0f * 0.5f) - 30 * 0.5f };

					节点面板->m_拾取区域大小 = { 30 + g左边插座大小.x, 60 };
					内部面板大小 = { 30,30 };
					节点面板->m_高比例 = 1;


					节点面板->m_独显按钮->f_setOriginalPos({});
					节点面板->m_拖拽到其他视口按钮->f_setOriginalPos({});
					节点面板->m_独显按钮->f_setOriginalSize({1});
					节点面板->m_拖拽到其他视口按钮->f_setOriginalSize({1});

					内部操控按钮宽度 = 0;

					break;
				}
				case E_节点类型::e_节点Type_框: {
					loc = {};
					内部面板大小 = 节点面板->f_getOriginalSize();
					节点面板->m_拾取区域大小 = 内部面板大小;

					节点面板->m_内部面板->f_setOriginalPos({});
					节点面板->m_内部面板->f_setPos({});

					节点面板->m_独显按钮->f_setOriginalPos({});
					节点面板->m_独显按钮->f_setOriginalSize({ 1 });
					//节点面板->m_独显按钮->f_setPos({});
					//节点面板->m_独显按钮->f_setSize({ 1 });
					节点面板->m_拖拽到其他视口按钮->f_setOriginalPos({});
					节点面板->m_拖拽到其他视口按钮->f_setOriginalSize({ 1 });
					//节点面板->m_拖拽按钮->f_setPos({});
					//节点面板->m_拖拽按钮->f_setSize({ 1 });
					内部操控按钮宽度 = 0;
					break;
				}
				default: {
					loc = { g左边插座大小.x, (60.0f * 0.5f) - 30 * 0.5f };

					节点面板->m_节点面板宽度 = width;
					节点面板->m_拾取区域大小.x = width;
					节点面板->m_拾取区域大小.y = 60;
					内部面板大小 = { 节点面板->m_拾取区域大小.x - g左边插座大小.x, 30 };
					节点面板->m_高比例 = 30.0 / 节点面板->m_拾取区域大小.x;


					节点面板->m_独显按钮->f_setOriginalPos(loc);
					节点面板->m_拖拽到其他视口按钮->f_setOriginalPos({ 节点面板->m_拾取区域大小.x - 10, loc.y });
					节点面板->m_独显按钮->f_setOriginalSize({ 10, 内部面板大小.y });
					节点面板->m_拖拽到其他视口按钮->f_setOriginalSize({ 10, 内部面板大小.y });


					节点面板->m_独显按钮->f_setPos(节点面板->m_独显按钮->f_getOriginalPos() * 节点面板->m_Scale.x);
					节点面板->m_独显按钮->f_setSize(节点面板->m_独显按钮->f_getOriginalSize() * 节点面板->m_Scale.x);

					内部操控按钮宽度 = 10 * 节点面板->m_Scale.x;
				}
		
			}

			节点面板->f_setOriginalSize(节点面板->m_拾取区域大小);
			节点面板->f_setSize(节点面板->m_拾取区域大小* 节点面板->m_Scale.x);

			节点面板->m_内部面板->f_setOriginalPos(loc);
			节点面板->m_内部面板->f_setOriginalSize(内部面板大小);



			vec2 wh = 节点面板->m_拾取区域大小 * 节点面板->m_Scale.x;
			节点面板->m_内部面板->f_setPos(节点面板->m_内部面板->f_getOriginalPos()* 节点面板->m_Scale.x);
			节点面板->m_内部面板->f_setSize(wh);


			节点面板->m_拖拽到其他视口按钮->f_setPos({ 节点面板->m_Size.x - 内部操控按钮宽度, loc.y * 节点面板->m_Scale.x });
			节点面板->m_拖拽到其他视口按钮->f_setSize({ 内部操控按钮宽度, wh.y });

			break;
		}
	}

}

void f_NodePlane_更新节点内部面板布局(C_节点面板* 节点面板, E_方向 方向) {
	switch (方向) {
	case E_方向::e_横向: {
		switch (节点面板->m_NodeData->m_Type)
		{
		case E_节点类型::e_节点Type_Reroute:
			节点面板->m_拾取区域大小 = { 50 + g插座宽度 * 2, 50 };
			//内部面板大小 = { 30, 30 };
			break;
		default:
			break;
		}
		break;
	}
	case E_方向::e_纵向: {
		break;
	}
	}
}

S_Bounding2D f_NodePlane_计算包含节点边界框(C_节点面板* 节点面板) {
	S_Bounding2D bound = { {100000000, 100000000}, {-100000000, -100000000} };

	uint32 num = 节点面板->m_NodeData->m_框包含节点.size();
	if (num) {
		auto* 区域内节点 = 节点面板->m_NodeData->m_框包含节点.data();

		for (uint32 i = 0; i < num; ++i) {
			if (区域内节点[i]->m_包含在多个视口的UI部件.size()) {
				C_节点面板* p = (C_节点面板*)(*(区域内节点[i]->m_包含在多个视口的UI部件.begin()));
				vec2 pos = p->f_getOriginalPos();

				bound.min = vec_Min(bound.min, pos - 20);
				bound.max = vec_Max(bound.max, pos + p->f_getOriginalSize() + 20);
			}
		}
	}
	else {
		bound.min = 节点面板->m_NodeData->m_坐标;
		bound.max = 节点面板->m_NodeData->m_坐标 + vec2{200,200};
	}
	
	return bound;
}










C_节点操作_移动节点::C_节点操作_移动节点(std::vector<C_节点基类*>& nodes, const vec2& 起始中心) {
	//m_记录初始坐标.clear();
	//m_连带节点记录初始坐标.clear();
	f_记录(nodes, 起始中心);
	
	for (auto& 主节点面板 : nodes) {
		//m_记录初始坐标.push_back(主节点面板->f_getPos() - 鼠标位置);
		//
		//switch (主节点面板->m_NodeData->m_Type) {
		//case E_节点类型::e_节点Type_框: {
		//	uint32 num = 主节点面板->m_NodeData->m_框包含节点.size();
		//	auto* 区域内节点 = 主节点面板->m_NodeData->m_框包含节点.data();
		//
		//	for (uint32 i = 0; i < num; ++i) {
		//		vec2 偏移 = f_NodePanel_get全局坐标(区域内节点[i], 主节点面板->m_父部件->m_扩展视口属性);
		//		m_连带节点记录初始坐标.push_back(偏移 - 鼠标位置);
		//	}
		//	break;
		//}
		//default:
		//	break;
		//}
	}
}

void C_节点操作_移动节点::f_撤销() {
	for (auto& e : m_Nodes) {
		e.m_node->m_坐标 = e.m_移动前坐标;
	}
}

void C_节点操作_移动节点::f_重做() {
	for (auto& e : m_Nodes) {
		e.m_node->m_坐标 = e.m_移动后坐标;
	}
}

void C_节点操作_移动节点::f_移动(const vec2& 标准坐标) {
	uint32 num = m_Nodes.size();
	auto* 移动节点 = m_Nodes.data();
	for (uint32 i = 0; i < num; ++i) {
		移动节点[i].m_node->m_坐标 = 标准坐标 + 移动节点[i].m_相对起始坐标;

		for (auto& panel : 移动节点[i].m_node->m_包含在多个视口的UI部件) {
			f_NodePlane_更新布局((C_节点面板*)panel);
		}
	}
}

void C_节点操作_移动节点::f_记录(std::vector<C_节点基类*> nodes, const vec2& 起始中心) {
	for (auto& 节点 : nodes) {
		S_节点移动记录 移动记录 = { 节点, 节点->m_坐标, {}, 节点->m_坐标 - 起始中心 };
		m_Nodes.push_back(移动记录);

		switch (节点->m_Type) {
			case E_节点类型::e_节点Type_框: {
				if (节点->m_框包含节点.size()) {
					f_记录(节点->m_框包含节点, 起始中心);
				}
				break;
			}
		}
	}
}






void f_NodePlane_鼠标设置节点坐标(C_节点面板* 节点面板, vec2 鼠标位置) {
	//判断是否加入到视口组件中
	if (节点面板->m_父部件) {

		节点面板->m_NodeData->m_坐标 = (鼠标位置 - 节点面板->m_父部件->m_扩展视口属性->m_中心) / 节点面板->m_父部件->m_扩展视口属性->m_比例;

		f_NodePlane_更新布局(节点面板);
	}
}

void f_NodePlane_设置后端节点坐标(C_节点面板* 节点面板, vec2 原始坐标) {
	节点面板->m_NodeData->m_坐标 = 原始坐标;

}

void f_NodePlane_更新布局(C_节点面板* 节点面板) {
	
	C_节点视口* view = (C_节点视口*)节点面板->m_父部件;

	//auto 方向 = view->m_节点树后端->m_布局方向;
	节点面板->f_setOriginalPos(节点面板->m_NodeData->m_坐标);
	节点面板->f_setPos(节点面板->m_NodeData->m_坐标 * 节点面板->m_父部件->m_扩展视口属性->m_比例 + 节点面板->m_父部件->m_扩展视口属性->m_中心);
	

	f_NodePlane_更新节点内部面板(节点面板);


	auto& outSocket = 节点面板->f_getOutSocket();
	uint32 outNum = outSocket.size();
	for (uint32 i = 0; i < outNum; ++i) {
		if (!outSocket[i]->m_SocketData) {
			std::cout<<"error : 不能操作节点插座 节点面板插座以释放" << std::endl;
			continue;
		}
		auto inSocket = outSocket[i]->m_SocketData->f_get链接到的输入插座();
		for (auto e : inSocket) {
			if (e->m_UI部件) ((C_ui节点插座*)(e->m_UI部件))->m_NodePlane->m_绘制属性更新 = true;
		}
	}

	//更新节点光联的其他视口
	auto& uis = 节点面板->m_NodeData->m_包含在多个视口的UI部件;
	for (auto it = uis.begin(); it != uis.end(); ) {
		if (((C_节点面板*)(*it))->m_节点当前所在视口 == nullptr) {
			it = uis.erase(it);
		}
		else {
			++it;
		}
	}
	//auto 后端 = static_cast<C_节点视口*>(节点面板->m_节点视口)->m_节点树后端;
	for (auto& e : 节点面板->m_NodeData->m_包含在多个视口的UI部件) {
		C_节点面板* plane = static_cast<C_节点面板*>(e);
		if (plane) {
			f_widget_单个部件裁剪(plane, plane->m_节点当前所在视口->m_裁剪大小, plane->m_节点当前所在视口->m_GlobalLoc);
			plane->m_绘制属性更新 = true;
		}
	}


	节点面板->m_绘制属性更新 = true;
	节点面板->m_父部件->m_绘制属性更新 = true;
}

void f_NodePlane_更新横向排列节点坐标(C_节点面板* 节点面板) {

}


void f_NodePanel_get边界框(const C_节点面板* 节点面板, mat2x4& point) {
	point.m0 = 节点面板->f_getOriginalPos();
	point.m0.x -= 30;
	point.m0.y -= 20;
	point.m2 = point.m0 + 节点面板->f_getOriginalSize();
	point.m2.x += 60;
	point.m2.y += 40;

	point.m1.x = point.m2.x;
	point.m1.y = point.m0.y;

	point.m3.x = point.m0.x;
	point.m3.y = point.m2.y;
}

void f_NodePanel_更新框(C_节点面板* 节点面板) {
	auto* 区域内节点 = 节点面板->m_NodeData->m_框包含节点.data();

	uint32 num = 节点面板->m_NodeData->m_框包含节点.size();
	for (uint32 i = 0; i < num; ++i) {
		C_节点面板* 内层框节点 = (C_节点面板*)*区域内节点[i]->m_包含在多个视口的UI部件.begin();

		switch (区域内节点[i]->m_Type) {
			case E_节点类型::e_节点Type_框: {
				f_NodePanel_更新框(内层框节点);
				break;
			}
		}
	}

	S_Bounding2D box = f_NodePlane_计算包含节点边界框(节点面板);

	节点面板->f_setOriginalSize(box.max - box.min);
	f_NodePlane_设置后端节点坐标(节点面板, box.min);

	f_NodePlane_更新布局(节点面板);

}

bool f_NodePanel_是否已在框内(const C_节点基类* 要添加到框的节点, const C_节点基类* 要对照框节点) {
	if (要对照框节点->m_框节点) {
		if (要对照框节点->m_框节点 == 要添加到框的节点) {
			return true;
		}

		return f_NodePanel_是否已在框内(要添加到框的节点, 要对照框节点->m_框节点);
	}
	else {
		if (要对照框节点 == 要添加到框的节点) {
			return true;
		}
	}
	return false;
}

















